Passed
Branch v15.x (de5209)
by Rafael S.
02:05
created

main.js ➔ unpack   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 17
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 4
eloc 11
c 2
b 0
f 0
nc 4
nop 3
dl 0
loc 17
rs 9.85
1
/*
2
 * Copyright (c) 2017-2018 Rafael da Silva Rocha.
3
 *
4
 * Permission is hereby granted, free of charge, to any person obtaining
5
 * a copy of this software and associated documentation files (the
6
 * "Software"), to deal in the Software without restriction, including
7
 * without limitation the rights to use, copy, modify, merge, publish,
8
 * distribute, sublicense, and/or sell copies of the Software, and to
9
 * permit persons to whom the Software is furnished to do so, subject to
10
 * the following conditions:
11
 *
12
 * The above copyright notice and this permission notice shall be
13
 * included in all copies or substantial portions of the Software.
14
 *
15
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
 *
23
 */
24
25
/**
26
 * @fileoverview The byte-data API.
27
 * @see https://github.com/rochars/byte-data
28
 */
29
30
/** @module byteData */
31
32
import endianness from 'endianness';
33
import utf8BufferSize from 'utf8-buffer-size';
34
import {pack as packUTF8, unpack as unpackUTF8} from 'utf8-buffer';
35
import Packer from './lib/packer.js';
36
import {validateNotUndefined, validateValueType} from './lib/validation.js';
37
38
/**
39
 * Read a string of UTF-8 characters from a byte buffer.
40
 * @param {!Uint8Array|!Array<number>} buffer A byte buffer.
41
 * @param {number=} index The buffer index to start reading.
42
 * @param {?number=} end The buffer index to stop reading.
43
 *    If end is null will read until the end of the buffer.
44
 * @return {string}
45
 */
46
export function unpackString(buffer, index=0, end=null) {
47
  return unpackUTF8(buffer, index, end);
48
}
49
50
/**
51
 * Write a string of UTF-8 characters as a byte buffer.
52
 * @param {string} str The string to pack.
53
 * @return {!Uint8Array|Array<number>} The buffer with the packed string written.
54
 */
55
export function packString(str) {
56
  /** type {Uint8Array|Array<number>} */
57
  let buffer;
58
  if (typeof Uint8Array === 'function') {
59
    buffer =  new Uint8Array(utf8BufferSize(str));
60
  } else {
61
    buffer = [];
62
  }
63
  packUTF8(str, buffer, 0);
64
  return buffer;
65
}
66
67
/**
68
 * Write a string of UTF-8 characters to a byte buffer.
69
 * @param {string} str The string to pack.
70
 * @param {!Uint8Array|!Array<number>} buffer The output buffer.
71
 * @param {number=} index The buffer index to start writing.
72
 *   Assumes zero if undefined.
73
 * @return {number} The next index to write in the buffer.
74
 */
75
export function packStringTo(str, buffer, index=0) {
76
  return packUTF8(str, buffer, index);
77
}
78
79
// Numbers
80
/**
81
 * Pack a number as a byte buffer.
82
 * @param {number} value The number.
83
 * @param {!Object} theType The type definition.
84
 * @return {!Array<number>} The packed value.
85
 * @throws {Error} If the type definition is not valid.
86
 * @throws {Error} If the value is not valid.
87
 */
88
export function pack(value, theType) {
89
  /** @type {!Array<number>} */
90
  let output = [];
91
  packTo(value, theType, output);
92
  return output;
93
}
94
95
/**
96
 * Pack a number to a byte buffer.
97
 * @param {number} value The value.
98
 * @param {!Object} theType The type definition.
99
 * @param {!Uint8Array|!Array<number>} buffer The output buffer.
100
 * @param {number=} index The buffer index to write. Assumes 0 if undefined.
101
 * @return {number} The next index to write.
102
 * @throws {Error} If the type definition is not valid.
103
 * @throws {Error} If the value is not valid.
104
 */
105
export function packTo(value, theType, buffer, index=0) {
106
  return packArrayTo([value], theType, buffer, index);
107
}
108
109
/**
110
 * Pack an array of numbers as a byte buffer.
111
 * @param {!Array<number>|!TypedArray} values The values.
112
 * @param {!Object} theType The type definition.
113
 * @return {!Array<number>} The packed values.
114
 * @throws {Error} If the type definition is not valid.
115
 * @throws {Error} If any of the values are not valid.
116
 */
117
export function packArray(values, theType) {
118
  /** @type {!Array<number>} */
119
  let output = [];
120
  packArrayTo(values, theType, output);
121
  return output;
122
}
123
124
/**
125
 * Pack a array of numbers to a byte buffer.
126
 * @param {!Array<number>|!TypedArray} values The value.
127
 * @param {!Object} theType The type definition.
128
 * @param {!Uint8Array|!Array<number>} buffer The output buffer.
129
 * @param {number=} index The buffer index to start writing.
130
 *   Assumes zero if undefined.
131
 * @return {number} The next index to write.
132
 * @throws {Error} If the type definition is not valid.
133
 * @throws {Error} If the value is not valid.
134
 */
135
export function packArrayTo(values, theType, buffer, index=0) {
136
  /** @type {Packer} */
137
  let packer = new Packer();
138
  packer.setUp(theType);
139
  let valuesLen = values.length;
140
  for (let i = 0; i < valuesLen; i++) {
141
    validateNotUndefined(values[i]);
142
    validateValueType(values[i]);
143
    /** @type {number} */
144
    let len = index + packer.offset;
145
    while (index < len) {
146
      index = packer.write(buffer, values[i], index);
147
    }
148
    if (theType.be) {
149
      endianness(
150
        buffer, packer.offset, index - packer.offset, index);
151
    }
152
  }
153
  return index;
154
}
155
156
/**
157
 * Unpack a number from a byte buffer.
158
 * @param {!Uint8Array|!Array<number>} buffer The byte buffer.
159
 * @param {!Object} theType The type definition.
160
 * @param {number=} index The buffer index to read. Assumes zero if undefined.
161
 * @return {number}
162
 * @throws {Error} If the type definition is not valid
163
 * @throws {Error} On bad buffer length.
164
 */
165
export function unpack(buffer, theType, index=0) {
166
  /** @type {Packer} */
167
  let packer = new Packer();
168
  packer.setUp(theType);
169
  if ((packer.offset + index) > buffer.length) {
170
    throw Error('Bad buffer length.');
171
  }
172
  if (theType.be) {
173
    endianness(buffer, packer.offset, index, index + packer.offset);
174
  }
175
  /** @type {number} */
176
  let value = packer.read(buffer, index);
177
  if (theType.be) {
178
    endianness(buffer, packer.offset, index, index + packer.offset);
179
  }
180
  return value;
181
}
182
183
/**
184
 * Unpack an array of numbers from a byte buffer.
185
 * @param {!Uint8Array|!Array<number>} buffer The byte buffer.
186
 * @param {!Object} theType The type definition.
187
 * @param {number=} index The buffer index to start reading.
188
 *   Assumes zero if undefined.
189
 * @param {number=} end The buffer index to stop reading.
190
 *   Assumes the buffer length if undefined.
191
 * @return {!Array<number>}
192
 * @throws {Error} If the type definition is not valid
193
 */
194
export function unpackArray(buffer, theType, index=0, end=buffer.length) {
195
  /** @type {!Array<number>} */
196
  let output = [];
197
  unpackArrayTo(buffer, theType, output, index, end);
198
  return output;
199
}
200
201
/**
202
 * Unpack a array of numbers to a typed array.
203
 * @param {!Uint8Array|!Array<number>} buffer The byte buffer.
204
 * @param {!Object} theType The type definition.
205
 * @param {!TypedArray|!Array<number>} output The output array.
206
 * @param {number=} index The buffer index to start reading.
207
 *   Assumes zero if undefined.
208
 * @param {number=} end The buffer index to stop reading.
209
 *   Assumes the buffer length if undefined.
210
 * @throws {Error} If the type definition is not valid
211
 */
212
export function unpackArrayTo(
213
    buffer, theType, output, index=0, end=buffer.length) {
214
  /** @type {Packer} */
215
  let packer = new Packer();
216
  packer.setUp(theType);
217
  /** @type {number} */
218
  let originalIndex = index;
219
  while ((end - index) % packer.offset) {
220
      end--;
221
  }
222
  if (theType.be) {
223
    endianness(buffer, packer.offset, index, end);
224
  }
225
  for (let i = 0; index < end; index += packer.offset) {
0 ignored issues
show
Unused Code introduced by
The loop variable i is initialized by the loop but not used in the test. Consider using another type of loop if this is the intended behavior.
Loading history...
226
    output[i] = packer.read(buffer, index);
227
    i++;
228
  }
229
  if (theType.be) {
230
    endianness(buffer, packer.offset, originalIndex, end);
231
  }
232
}
233